/*
  Copyright 2006 by Sean Luke
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/


package ec.app.deferEvalCoevolve1;
import ec.Individual;
import ec.BreedingPipeline;
import ec.EvolutionState;
import ec.Population;
import ec.util.*;

/* 
 * DeferEval_Breeder_simple.java
 * 
 * Created: Tue Aug 10 21:00:11 1999
 * By: Sean Luke
 */

/**
 * Breeds each subpopulation separately, with no inter-population exchange,
 * and using a generational approach.  A DeferEval_Breeder_simple may have multiple
 * threads; it divvys up a subpopulation into chunks and hands one chunk
 * to each thread to populate.  One array of BreedingPipelines is obtained
 * from a population's Species for each operating breeding thread.
 *
 * Prior to breeding a subpopulation, a DeferEval_Breeder_simple may first fill part of the new
 * subpopulation up with the best <i>n</i> individuals from the old subpopulation.
 * By default, <i>n</i> is 0 for each subpopulation (that is, this "elitism"
 * is not done).  The elitist step is performed by a single thread.
 *
 <p><b>Parameters</b><br>
 <table>
 <tr><td valign=top><tt><i>base</i>.elite.<i>i</i></tt><br>
 <font size=-1>int >= 0 (default=0)</font></td>
 <td valign=top>(the number of elitist individuals for subpopulation <i>i</i>)</td></tr>
 </table>
 *
 *
 * @author Sean Luke
 * @version 1.0 
 */

public class DeferEval_Breeder_simple extends DeferEval_Breeder_base
    {

    /** A private helper function for breedPopulation which loads elites into
        a subpopulation. */
	@Override
    public void loadElites(EvolutionState state, Population newpop) {
		// are our elites small enough?
		for (int x = 0; x < state.population.subpops.length; x++)
			if (elite[x] > state.population.subpops[x].individuals.length)
				state.output.error("The number of elites for subpopulation "
						+ x + " exceeds the actual size of the subpopulation",
						new Parameter(EvolutionState.P_BREEDER).push(P_ELITE)
								.push("" + x));
		state.output.exitIfErrors();

		// we assume that we're only grabbing a small number (say <10%), so
		// it's not being done multithreaded
		for (int sub = 0; sub < state.population.subpops.length; sub++) {
        	BreedingPipeline bp;
        	bp = (BreedingPipeline)(state.population.subpops[sub].species.pipe_prototype.clone());
        	DeferEval_TournamentSelection_simple ts2 = (DeferEval_TournamentSelection_simple) bp.sources[0];
        	
			if (elite[sub] == 1) {
				Individual choice[] = new Individual[elite[sub]];
				ts2.bestN(choice, elite[sub], sub, state);
				// int best = 0;
				// Individual[] oldinds =
				// state.population.subpops[sub].individuals;
				// for(int x=1;x<oldinds.length;x++)
				// if (oldinds[x].fitness.betterThan(oldinds[best].fitness))
				// best = x;
				Individual[] inds = newpop.subpops[sub].individuals;
				inds[inds.length - 1] = (Individual) (choice[0].clone());
			} else if (elite[sub] > 0) // we'll need to sort
			{
				Individual choice[] = new Individual[elite[sub]];

				ts2.bestN(choice, elite[sub], sub, state);

				// int[] orderedPop = new
				// int[state.population.subpops[sub].individuals.length];
				// for(int
				// x=0;x<state.population.subpops[sub].individuals.length;x++)
				// orderedPop[x] = x;
				//
				// // sort the best so far where "<" means "not as fit as"
				// QuickSort.qsort(orderedPop, new
				// EliteComparator(state.population.subpops[sub].individuals));
				// // load the top N individuals

				Individual[] inds = newpop.subpops[sub].individuals;
				Individual[] oldinds = state.population.subpops[sub].individuals;
				// for(int x=inds.length-elite[sub];x<inds.length;x++) {
				// inds[x] = (Individual)(oldinds[orderedPop[x]].clone());
				// }
				for (int i = 0; i < elite[sub]; i++) {
					int targInd;
					targInd = inds.length - elite[sub] + i;
					inds[targInd] = (Individual) (choice[i].clone());
				}
			}
		}
	}
}